package com.Sake.common.annotation;

import com.Sake.common.utils.ip.DateUtils;
import com.Sake.common.utils.ip.HttpUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author zsh
 * @date 2021.6.10
 */
@Component
@Aspect
public class LoggerAop {



    @Autowired
    private HttpUtils httpUtils;

    @Autowired
    private DateUtils dateUtils;

    /**
     * 日志
     */
    private final org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 配置切入点
     */
    @Pointcut("execution( * com.Sake.*.controller..*Controller.*(..))")
    public void pointcut(){
    }

    /**
     * 环绕通知
     *
     * @param loggerManage
     * @param
     * @throws Throwable
     */
    @Around("@annotation(loggerManage)")
    public Object aroundLogger(ProceedingJoinPoint joinPoint, LoggerManage loggerManage) throws Throwable {
        // 当前方法执行结果
        Object result = null;
        //开始时间
        Long beginTime = dateUtils.getCurrentDate();
        //开发环境打印日志，生成环境不打印日志
        logger.info("执行 *********************" + loggerManage.moduleName() + " " + loggerManage.option() + " *********************开始");
        logger.info("传入参数: "+parseParames(joinPoint.getArgs()).toString());
        logger.info("操作时间: " + dateUtils.timeStampToYMDHMS(beginTime));
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        logger.info("操作ip: " + httpUtils.getRemortIp(request));
        logger.info("操作URL: " + httpUtils.getRemortUrl(request));
        logger.info("当前用户ID: " + httpUtils.getCurrentUser(request));
        logger.info("操作类及方法: " + getClassMethod(request, joinPoint));
        //目标方法执行
        result = joinPoint.proceed();
        logger.info("响应时间: " + (dateUtils.getCurrentDate() - beginTime) + " 毫秒");
        logger.info("响应结果: " + result);
        logger.info("执行 *********************" + loggerManage.moduleName() + " " + loggerManage.option() + " *********************结束");

        return result;
    }
    /**
     * 获取当前请求的具体类和方法
     *
     * @param request
     * @return
     */
    public String getClassMethod(HttpServletRequest request, JoinPoint joinPoint) {
        return joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
    }

    /**
     *  异常信息打印
     * @param jp
     * @param ex
     */
    @AfterThrowing(pointcut ="pointcut()",throwing = "ex")
    public void afterThrowing(JoinPoint jp, Exception ex){
        String methodName = jp.getSignature().getName();
        Object[] args = jp.getArgs();
        logger.error("执行方法：{}  异常！--------------- 入参：{} ------------- 异常信息如下：",methodName,args,ex);
        //错误日志发送到开发人员邮箱
            StringBuilder builder = new StringBuilder();
            builder.append("执行方法：")
                    .append(methodName)
                    .append("<br>入参：")
                    .append(parseParames(args))
                    .append("<br>异常信息如下：<br>")
                    .append(ex.getMessage())
                    .append("<br>错误原因：")
                    .append(ex.getCause().getMessage())
                    .append("<br>错误代码行数：")
                    .append(ex.getCause().getStackTrace()[0]);
        logger.error(builder.toString());

    }

    /**
     * 解析目标方法的参数对象
     *
     * @param parames
     * @return
     */
    private String parseParames(Object[] parames) {
        if (null == parames || parames.length <= 0) {
            return "";
        }
        StringBuffer param = new StringBuffer("[{");
        for (int i = 0; i < parames.length; i++) {
            Object object = parames[i];
            if (i + 1 == parames.length) {
                param.append(object);
            } else {
                param.append(object + ",");
            }
        }
        param.append("}]");
        return param.toString();
    }
}
